﻿using System;

// XNA lib
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;



//Oak Engine Lib
using OakEngine.GameState;
using OakEngine.Input;
using Microsoft.Xna.Framework.Input;

namespace MainJumpFleet.GameStates
{
    /*
    public struct MotherShip
    {
        public JumpFleetGameLib.xSprite.StaticSprite sprite;
        public float rotationSpeed;
        public float movementSpeed;
        public Vector2 forwardVectorNormalized;
        public Vector2 waypoint1;
        public Vector2 waypoint2;
        public Vector2 waypoint3;
    }

    public struct SatelliteShip
    {
        public JumpFleetGameLib.xSprite.StaticSprite sprite;                
    }
    */
 
   public class NewShipMovementGameScreenState : OAK_IGameState
    {
        #region OAK_IGameState Members
        SpriteBatch batch;
        SpriteFont mainMenuFont;
                      
        // holds the SpriteManager object
        private JumpFleetGameLib.xSprite.SpriteManager spriteManager;

        MotherShip motherShip;        
        
        SpriteFont debugFont;
        Vector2 leftStickPosition;
        float leftStickAngleRadians;
        bool isLeftStickXZero;
        bool isLeftStickYZero;

        float rotationVectorAdjustment;

        float angleVarianceAllowed;

        bool debugMode = false;

        public NewShipMovementGameScreenState()
        {
            Enter();
        }


        public void Enter()
        {
            mainMenuFont = CGame.CGame.GetInstance().Content.Load<SpriteFont>("Fonts\\mainMenuFont");
            batch = CGame.CGame.GetInstance().SpriteBatch;
            
            // loads the debug font
            debugFont = CGame.CGame.GetInstance().Content.Load<SpriteFont>(@"Fonts\mainMenuFont");

            // creates the SpriteManager object
            spriteManager = new JumpFleetGameLib.xSprite.SpriteManager();
            
            // creates the sprite templates            
            spriteManager.CreateStaticSpriteTemplate("MotherShip", CGame.CGame.GetInstance().Content.Load<Texture2D>(@"textures\ship3_128x76"), 0, 0, 128, 76, Color.White, 255, 0, JumpFleetGameLib.xSprite.RotationAnchorPoint.Center, 1.0f, SpriteEffects.None, 0.300f);
            
            // sets up the mother ship's members
            motherShip = new MotherShip();
            motherShip.sprite = spriteManager.CreateNewStaticSpriteFromTemplate("MotherShip");
            motherShip.sprite.Visible = true;
            motherShip.sprite.DrawPosition = new Vector2(CGame.CGame.GetInstance().Device.Viewport.Width / 2, CGame.CGame.GetInstance().Device.Viewport.Height / 2);
            motherShip.sprite.RotationAmount = MathHelper.ToRadians(0f);
            motherShip.rotationSpeed = 0.1f;
            motherShip.movementSpeed = 50.0f;            
            motherShip.forwardVectorNormalized = JumpFleetGameLib.VectorTransformations.RotateVector(motherShip.sprite.RotationAmount + rotationVectorAdjustment);
            motherShip.waypoint1 = motherShip.sprite.DrawPosition + new Vector2(-100.0f, 50.0f);
            motherShip.waypoint2 = motherShip.sprite.DrawPosition + new Vector2(0, 128.0f);
            motherShip.waypoint3 = motherShip.sprite.DrawPosition + new Vector2(100.0f, 50.0f);          

            // sets the default flags to true
            isLeftStickXZero = true;
            isLeftStickYZero = true;

            // JumpFleetGameLib.VectorTransformations.RotateVector() starts with 0 degrees pointing at (0, -1)
            // but we need 0 degrees to point at (1, 0)
            // add this to the ship rotation as we pass it into JumpFleetGameLib.VectorTransformations.RotateVector()
            rotationVectorAdjustment = MathHelper.ToRadians(90);

            // ship rotation angle will rarely match the exact angle of the left stick
            // adding and subtracting this amount from the left stick angle gives us
            // a range to check the ship's rotation angle against for forward movement
            angleVarianceAllowed = MathHelper.ToRadians(1.0f);
        }

        public bool Input(OAK_InputManager input)
        {
            if (input.Pressed(Keys.Escape) || input.Pressed(Buttons.Back, 0))
                CGame.CGame.GetInstance().ChangeState(new MainMenuState());

            // stores the left stick position
            leftStickPosition = input.LeftStickPosition(0);          

            return false;
        }

        public void Update(GameTime dt)
        {
            // sets flags to tell whether the left stick was pressed in a direction or not
            if ((leftStickPosition.X < 0) || (leftStickPosition.X > 0))
                isLeftStickXZero = false;
            else
                isLeftStickXZero = true;

            if ((leftStickPosition.Y < 0) || (leftStickPosition.Y > 0))
                isLeftStickYZero = false;
            else
                isLeftStickYZero = true;            

            // gets the angle the left stick is positioned to
            leftStickAngleRadians = (float)Math.Atan2(leftStickPosition.Y * 5, leftStickPosition.X * 5);

            // translates rotation to correct range of -180 to 180 degrees
            if (motherShip.sprite.RotationAmount > MathHelper.ToRadians(180f))
            {
                float newRotationRadians = MathHelper.ToRadians(180f) - (motherShip.sprite.RotationAmount - MathHelper.ToRadians(180f));
                motherShip.sprite.RotationAmount = newRotationRadians * -1;                 
            }
            else if (motherShip.sprite.RotationAmount < MathHelper.ToRadians(-180f))
            {
                float newRotationRadians = MathHelper.ToRadians(180f) + motherShip.sprite.RotationAmount;
                motherShip.sprite.RotationAmount = MathHelper.ToRadians(180f) - Math.Abs(newRotationRadians);
            }

            // translates 180 degrees to -180 degrees to match the left stick input
            if (motherShip.sprite.RotationAmount == MathHelper.ToRadians(180f))
                motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount * -1;

            // checks the flags to make sure the left stick was pressed in a direction
            if ((isLeftStickXZero == false) || (isLeftStickYZero == false))
            {
                
                if ((motherShip.sprite.RotationAmount <= 0) && (leftStickAngleRadians >= 0))
                {
                    // compute the CCW distance
                    float distanceCCW = (MathHelper.ToRadians(180f) - Math.Abs(leftStickAngleRadians)) + (MathHelper.ToRadians(180f) - Math.Abs(motherShip.sprite.RotationAmount));

                    // compute the CW distance
                    float distanceCW = (Math.Abs(leftStickAngleRadians) - 0) + (Math.Abs(motherShip.sprite.RotationAmount) - 0);

                    // compare CCW to CW to see which distance is shorter
                    if (distanceCCW <= distanceCW)
                    {                     
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount - (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                    else
                    {                     
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount + (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                }

                if ((motherShip.sprite.RotationAmount >= 0) && (leftStickAngleRadians <= 0))
                {
                    // compute CCW distance
                    float distanceCCW = (Math.Abs(leftStickAngleRadians) - 0) + (Math.Abs(motherShip.sprite.RotationAmount) - 0);

                    // compute CW distance
                    float distanceCW = (MathHelper.ToRadians(180f) - Math.Abs(leftStickAngleRadians)) + (MathHelper.ToRadians(180f) - Math.Abs(motherShip.sprite.RotationAmount));

                    // compare CCW to CW to see which distance is shorter
                    if (distanceCCW <= distanceCW)
                    {                     
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount - (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                    else
                    {                        
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount + (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                }

                if (((leftStickAngleRadians < 0) && (motherShip.sprite.RotationAmount <= 0)) || ((leftStickAngleRadians > 0) && (motherShip.sprite.RotationAmount >= 0)))
                {
                    float distance = leftStickAngleRadians - motherShip.sprite.RotationAmount;

                    if (distance <= 0)
                    {                        
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount - (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                    else
                    {                        
                        motherShip.sprite.RotationAmount = motherShip.sprite.RotationAmount + (motherShip.rotationSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                    }
                }

                // rotate the ship's forward vector
                motherShip.forwardVectorNormalized = JumpFleetGameLib.VectorTransformations.RotateVector(motherShip.sprite.RotationAmount + rotationVectorAdjustment);

                // move the ship forward if the ship's rotation angle is within 
                // the left stick angle plus or minus the allowed variance
                if ((motherShip.sprite.RotationAmount >= leftStickAngleRadians - angleVarianceAllowed) && (motherShip.sprite.RotationAmount <= leftStickAngleRadians + angleVarianceAllowed))
                {
                    motherShip.sprite.DrawPosition += new Vector2(motherShip.forwardVectorNormalized.X * motherShip.movementSpeed * (float)dt.ElapsedGameTime.TotalSeconds, motherShip.forwardVectorNormalized.Y * motherShip.movementSpeed * (float)dt.ElapsedGameTime.TotalSeconds);
                }

            }
        }

        public void Render()
        {
            // ends the SpriteBatch from CGame
            batch.End();

            CGame.CGame.GetInstance().Device.Clear(Color.Black);            

            // starts the local SpriteBatch
            batch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

            // let the SpriteManager do it's job            
            spriteManager.Draw(batch);

            // debug info
            if (debugMode == true)
            {
                batch.DrawString(debugFont, "Left Stick Position:" + leftStickPosition.ToString(), new Vector2(10, 10), Color.White);
                batch.DrawString(debugFont, "Forward Vector:" + motherShip.forwardVectorNormalized.ToString(), new Vector2(10, 60), Color.White);
                batch.DrawString(debugFont, "Left Stick Angle (rad):" + leftStickAngleRadians.ToString(), new Vector2(10, 110), Color.White);
                float leftStickAngleDegrees = MathHelper.ToDegrees(leftStickAngleRadians);
                batch.DrawString(debugFont, "Left Stick Angle (deg):" + leftStickAngleDegrees.ToString(), new Vector2(10, 160), Color.White);
                batch.DrawString(debugFont, "Ship Rotation (rad):" + motherShip.sprite.RotationAmount.ToString(), new Vector2(10, 210), Color.White);
                batch.DrawString(debugFont, "Ship Rotation (deg):" + MathHelper.ToDegrees(motherShip.sprite.RotationAmount).ToString(), new Vector2(10, 260), Color.White);
                batch.DrawString(debugFont, "isLeftStickXZero: " + isLeftStickXZero.ToString(), new Vector2(10, 310), Color.White);
                batch.DrawString(debugFont, "isLeftStickYZero: " + isLeftStickYZero.ToString(), new Vector2(10, 360), Color.White);
            }

            // ends the local SpriteBatch
            batch.End();
      
            // starts the SpriteBatch again so I don't break the other GameStates
            batch.Begin();
        }

        public void Exit()
        {
        }

        #endregion
    }
}
